package main

import (
	"context"
	"fmt"
	"sync"
	"time"
)

type Task struct {
	ID       uint64
	Name     string
	Handler  func(ctx context.Context) interface{}
	Callback TaskCallback
	Status   TaskStatus
	Canceled bool
	Results  interface{}
	Timeout  time.Duration
}

type TaskStatus int
type TaskCallback func(task *Task, status TaskStatus)

const (
	TaskStatusRunning TaskStatus = iota
	TaskStatusFinished
	TaskStatusCancelled
)

type Robot struct {
	task     []*Task
	taskChan chan *Task
	lock     sync.Mutex
}

func NewRobot() *Robot {
	return &Robot{
		task:     make([]*Task, 10),
		taskChan: make(chan *Task),
	}
}

func (r *Robot) Start() {
	go r.run()
}

func (r *Robot) Stop() {
	close(r.taskChan)
}

func (r *Robot) AddTask(task *Task) {
	r.lock.Lock()
	defer r.lock.Unlock()
	r.taskChan <- task
}

func (r *Robot) run() {
	for {
		task := <-r.taskChan
		go r.doTask(task)
	}
}

func (r *Robot) doTask(task *Task) {

	timer := time.NewTimer(task.Timeout)
	doneChan := make(chan bool)
	ctx, cancel := context.WithTimeout(context.Background(), task.Timeout)
	defer cancel()

	go func() {
		task.Handler(ctx)
		doneChan <- true
	}()

	select {

	case <-doneChan:
		// fmt.Println("完成")
		fmt.Printf("Task %d: %s finished\n", task.ID, task.Name)
		task.Status = TaskStatusFinished
		// 回调任务执行情况
		if task.Callback != nil {
			task.Callback(task, task.Status)
		}
		timer.Stop()
		return
	case <-timer.C:
		fmt.Printf("Task %d: %s Canceled\n", task.ID, task.Name)
		task.Status = TaskStatusCancelled
		task.Canceled = false
		// 回调任务执行情况
		if task.Callback != nil {
			task.Callback(task, task.Status)
		}
		timer.Stop()
		return
	}

}

func main() {
	r := NewRobot()
	r.Start()

	// 添加任务
	r.AddTask(&Task{
		ID:   1,
		Name: "Task 1",
		Handler: func(ctx context.Context) interface{} {
			fmt.Println("Task 1 running...")
			time.Sleep(6 * time.Second)
			fmt.Println("Task 1 run doing")
			return nil
		},
		Callback: func(task *Task, status TaskStatus) {
			fmt.Println("Task 1 status:", status)
		},
		Timeout: 3 * time.Second,
	})

	// 添加任务
	r.AddTask(&Task{
		ID:   2,
		Name: "Task 2",
		Handler: func(ctx context.Context) interface{} {
			fmt.Println("Task 2 running...")
			time.Sleep(2 * time.Second)
			fmt.Println("Task 2 run doing")
			return nil
		},
		Callback: func(task *Task, status TaskStatus) {
			fmt.Println("Task 2 status:", status)
		},
		Timeout: 3 * time.Second,
	})

	// 等待任务结束
	time.Sleep(10 * time.Second)
	r.Stop()
}
